//
// Created by Zsir on 2025/8/22.
//

#include "EpollPoller.h"
#include "Channel.h"
#include "EventLoop.h"
#include <unistd.h>
#include <string.h>
#include <iostream>

EpollPoller::EpollPoller(EventLoop* loop)
    : ownerLoop_(loop),
      epollfd_(epoll_create1(EPOLL_CLOEXEC)),
      events_(kInitEventListSize) {
    if (epollfd_ < 0) {
        std::cerr << "EpollPoller::EpollPoller - 调用 epoll_create1 失败" << std::endl;
        abort();
    }
}

EpollPoller::~EpollPoller() {
    close(epollfd_);
}

void EpollPoller::poll(int timeoutMs, ChannelList* activeChannels) {
    int numEvents = epoll_wait(epollfd_, &*events_.begin(),
                               static_cast<int>(events_.size()), timeoutMs);
    if (numEvents > 0) {
        fillActiveChannels(numEvents, activeChannels);
        if (static_cast<size_t>(numEvents) == events_.size()) {
            events_.resize(events_.size() * 2);
        }
    } else if (numEvents == 0) {
        // timeout
    } else {
        std::cerr << "EpollPoller::poll() - epoll_wait 出错" << std::endl;
    }
}

void EpollPoller::updateChannel(Channel* channel) {
    const int fd = channel->fd();
    if (channels_.find(fd) == channels_.end()) {
        channels_[fd] = channel;
        update(EPOLL_CTL_ADD, channel);
    } else {
        update(EPOLL_CTL_MOD, channel);
    }
}

void EpollPoller::removeChannel(Channel* channel) {
    const int fd = channel->fd();
    channels_.erase(fd);
    update(EPOLL_CTL_DEL, channel);
}

void EpollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const {
    for (int i = 0; i < numEvents; ++i) {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);
    }
}

void EpollPoller::update(int operation, Channel* channel) {
    epoll_event event;
    memset(&event, 0, sizeof(event));
    event.events = channel->events();
    event.data.ptr = channel;

    int fd = channel->fd();
    if (epoll_ctl(epollfd_, operation, fd, &event) < 0) {
        std::cerr << "epoll_ctl 失败，op=" << operation << " fd=" << fd << std::endl;
    }
}